#ifndef SCON_RSULT_TEST_H_
#define SCON_RESULT_TEST_H_

#include "scon_result.h"

#include "gtest/gtest.h"

template<class InputIter> static ::testing::AssertionResult ArraysIsEqual(InputIter begin1, InputIter end1, InputIter begin2) {
	InputIter it1 = begin1;
	InputIter it2 = begin2;
	while(it1 != end1) {
		if (*it1 != *it2) {
			return ::testing::AssertionFailure() << "Arrays is not equal";
		}/* end of if */

		++it1;
		++it2;
	}//end of while

	return ::testing::AssertionSuccess();
}//end of template<class InputIter> ::testing::AssertionResult ArraysIsEqual()

namespace SCon {

class ResultTest: public ::testing::Test {
public:
	std::string errorMessage;

	virtual void SetUp() {
		errorMessage = "";
	}//end of virtual void SetUp()

	virtual void TearDown() {}//end of virtual void TearDown()

};//end of declaration class ResultTest: public ::testing::Test

TEST_F(ResultTest, FutureResult_InitializeTest){
//тестируем функцию FutureResult::Initialize();
	int size;
	int* actualDataSize = &size;
	FutureResult res;
	unsigned char* buf = res.Initialize(INVALID_HANDLE_VALUE, 1, actualDataSize);
	EXPECT_TRUE(buf == 0);
	buf = res.Initialize(INVALID_HANDLE_VALUE, 1, actualDataSize, 0, &errorMessage);
	EXPECT_TRUE(buf == 0);
	EXPECT_STREQ(errorMessage.c_str(), "Bad parameter 'event'"); 


	HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
	FutureResult res1;
	buf = res1.Initialize(event, 0, actualDataSize);
	EXPECT_TRUE(buf == 0);
	buf = res1.Initialize(event, 0, actualDataSize, 0, &errorMessage);
	EXPECT_TRUE(buf == 0);
	EXPECT_STREQ(errorMessage.c_str(), "Bad parameter 'dataSize'"); 

	FutureResult res2;
	buf = res2.Initialize(event, 1, 0);
	EXPECT_TRUE(buf == 0);
	buf = res2.Initialize(event, 1, 0, 0, &errorMessage);
	EXPECT_TRUE(buf == 0);
	EXPECT_STREQ(errorMessage.c_str(), "Bad parameter 'actualDataSize'"); 

	FutureResult res3;
	buf = res3.Initialize(event, 1024, actualDataSize);
	EXPECT_TRUE(res3.operationIsDone_ == event);
	EXPECT_TRUE(res3.dataSize_ == 1024);
	EXPECT_TRUE(res3.actualDataSize_ == actualDataSize);
	EXPECT_TRUE(res3.message_ != 0);
	EXPECT_TRUE(res3.message_ == buf);
	EXPECT_TRUE(res3.isOwnedToBuffer_);

	unsigned char buf1[1024];
	FutureResult res4;
	buf = res4.Initialize(event, 1024, actualDataSize, buf1);
	EXPECT_TRUE(res4.operationIsDone_ == event);
	EXPECT_TRUE(res4.dataSize_ == 1024);
	EXPECT_TRUE(res4.actualDataSize_ == actualDataSize);
	EXPECT_TRUE(res4.message_ == buf1);
	EXPECT_TRUE(res4.message_ == buf);
	EXPECT_TRUE(!res4.isOwnedToBuffer_);

	CloseHandle(event);
}

TEST_F(ResultTest, FutureResult){
//тестируем конструктор класса FutureResult
	int size;
	int* actualDataSize = &size;
	FutureResult(INVALID_HANDLE_VALUE, 1, actualDataSize, 0, &errorMessage);
	EXPECT_STREQ(errorMessage.c_str(), "Bad parameter 'event'"); 

	HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
	FutureResult(event, 0, actualDataSize, 0, &errorMessage);
	EXPECT_STREQ(errorMessage.c_str(), "Bad parameter 'dataSize'"); 

	FutureResult(event, 1, 0, 0, &errorMessage);
	EXPECT_STREQ(errorMessage.c_str(), "Bad parameter 'actualDataSize'"); 

	FutureResult res(event, 1024, actualDataSize);
	EXPECT_TRUE(res.operationIsDone_ == event);
	EXPECT_TRUE(res.dataSize_ == 1024);
	EXPECT_TRUE(res.message_ != 0);
	EXPECT_TRUE(res.isOwnedToBuffer_);

	unsigned char buf[1024];
	FutureResult res1(event, 1024, actualDataSize, buf);
	EXPECT_TRUE(res1.operationIsDone_ == event);
	EXPECT_TRUE(res1.dataSize_ == 1024);
	EXPECT_TRUE(res1.message_ != 0);
	EXPECT_TRUE(!res1.isOwnedToBuffer_);

	CloseHandle(event);
}

TEST_F(ResultTest, FutureResult_CopyConstructorTest){
//тестируем копирующий консруктор класса FutureResult
	HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
	int size = 20;
	int* actualDataSize = &size;
	FutureResult res(event, 20, actualDataSize);
	unsigned char* resMessage = res.message_;
	FutureResult copyRes = res;
	EXPECT_TRUE(copyRes.operationIsDone_ == event);
	EXPECT_TRUE(copyRes.message_ == resMessage);
	EXPECT_TRUE(copyRes.dataSize_ == 20);
	EXPECT_TRUE(copyRes.actualDataSize_ == actualDataSize);
	EXPECT_TRUE(copyRes.isOwnedToBuffer_ == true);
	EXPECT_TRUE(res.operationIsDone_ == INVALID_HANDLE_VALUE);
	EXPECT_TRUE(res.message_ == 0);
	EXPECT_TRUE(res.dataSize_ == 0);
	EXPECT_TRUE(res.actualDataSize_ == 0);
	EXPECT_TRUE(res.isOwnedToBuffer_ == false);

	CloseHandle(event);
}

TEST_F(ResultTest, FutureResult_AssignmentOperatorTest){
//тестируем оператор присваивания
	HANDLE event1 = CreateEvent(NULL, FALSE, FALSE, NULL);
	HANDLE event2 = CreateEvent(NULL, FALSE, FALSE, NULL);
	int size1 = 20;
	int* actualDataSize1 = &size1;
	int size2 = 10;
	int* actualDataSize2 = &size2;
	unsigned char buf[10];
	FutureResult res1(event1, 20, actualDataSize1, buf);
	FutureResult res2(event2, 10, actualDataSize2);
	res2 = res1;
	EXPECT_TRUE(res2.operationIsDone_ == event1);
	EXPECT_TRUE(res2.message_ == buf);
	EXPECT_TRUE(res2.dataSize_ == 20);
	EXPECT_TRUE(res2.actualDataSize_ == actualDataSize1);
	EXPECT_TRUE(res2.isOwnedToBuffer_ == false);
	EXPECT_TRUE(res1.operationIsDone_ == INVALID_HANDLE_VALUE);
	EXPECT_TRUE(res1.message_ == 0);
	EXPECT_TRUE(res1.dataSize_ == 0);
	EXPECT_TRUE(res1.actualDataSize_ == 0);
	EXPECT_TRUE(res1.isOwnedToBuffer_ == false);

	CloseHandle(event1);
	CloseHandle(event2);
}

TEST_F(ResultTest, FutureResult_IsDone){
//тестируем функцию FutureResult::IsDone()
	HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
	int size = 10;
	int* actualSize = &size;
	unsigned char buf[10] = {0};
	FutureResult res(event, 10, actualSize, buf);

	bool operationIsDone = res.IsDone();
	EXPECT_TRUE(!operationIsDone);

	SetEvent(event);
	operationIsDone = res.IsDone();
	EXPECT_TRUE(operationIsDone);

	CloseHandle(event);
}

TEST_F(ResultTest, FutureResult_GetResultTest){
//тестируем функцию FutureResult::GetResult()
#ifdef __SCON_DEBUG__
#define _D_GetResultTest_ 1
#else
#define _D_GetResultTest_ 0
#endif

	HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
	int size = 50;
	int* actualDataSize = &size;
	FutureResult res;
	unsigned char* buf = res.Initialize(event, 100, actualDataSize);
	unsigned char copyBuf[100];
	for (int i = 0; i < size; ++i) {
		buf[i] = i;
	}//end of for
	SetEvent(event);
	int actualSize = res.GetResult(copyBuf);
	EXPECT_EQ(actualSize, size);
	EXPECT_TRUE(ArraysIsEqual(buf, buf + *actualDataSize, copyBuf));

	SetEvent(event);
	actualSize = res.GetResult();
	EXPECT_EQ(actualSize, size);

	CloseHandle(event);
}

} /* SCon */ 

#endif /* end of include guard: SCON_RESULT_TEST_H_ */

